package conexao;

import java.io.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.*;
import recados.Recados;

public class Http extends Canvas implements CommandListener, Runnable {

    private static final int NORMAL = 0;
    private static final int ARQUIVO = 1;
    private int tipo = NORMAL;
    //GUI
    private String mensagem = "Processando";
    private int dots = 1;
    private Timer mytimer;
    private final Command cmdCancelar;
    //Conexao
    private HttpConnection conn;
    private DataOutputStream out;
    private DataInputStream in;
    //URL
    private String url;
    private Hashtable parametros;
    //Espera pelo resultado da conexao
    private HttpListener listener;
    //Para a conexao
    private boolean requestStop;
    //Anexo
    private String campoArquivo;
    private String nomeArquivo;
    private String tipoArquivo;
    private DataInputStream arquivo;
    //Post
    private byte[] data;
    private int tamanho;

    public Http(String titulo) {
        setTitle(titulo);

        cmdCancelar = new Command("Cancelar", Command.STOP, 0);

        addCommand(cmdCancelar);
        setCommandListener(this);

        parametros = new Hashtable();
        mytimer = new Timer();
    }

    public void run() {
        while (!requestStop) {
            repaint();
        }
    }

    private class doPoster extends TimerTask {

        public void run() {
            try {
                parametros.put("versao", "3.5.3");
                conecta();
                if (requestStop) {
                    return;
                }
                envia();
                if (requestStop) {
                    return;
                }
                retorna();
                if (requestStop) {
                    return;
                }
                listener.requisicaoConcluida(in);
            } catch (Exception e) {
                e.printStackTrace();
                if (!requestStop) {
                    listener.falhaRequisiçao("Nâo é possivel conectar");
                }
            } finally {
                requestStop = true;
                closeAll();
            }
        }

        public void conecta() throws IOException {
            conn = (HttpConnection) Connector.open(url, Connector.READ_WRITE, tipo == NORMAL);
            conn.setRequestMethod(HttpConnection.POST);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0) Gecko/20100101 Firefox/10.0");
            conn.setRequestProperty("Connection", "close");
        }

        private byte[] getBytes() {
            Enumeration e = parametros.keys();

            StringBuffer dados = new StringBuffer();

            while (e.hasMoreElements()) {
                String campo = (String) e.nextElement();
                String valor = (String) parametros.get(campo);
                dados.append("&").append(campo);
                dados.append("=");
                dados.append(valor);
            }

            return dados.deleteCharAt(0).toString().getBytes();
        }

        private void envia() throws IOException {
            boolean flush = Recados.getInstance().config.isFlush();
            conn.setRequestProperty("Content-Language", "pt-BR");

            byte[] enviar = null;

            if (tipo == NORMAL) {
                conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

                enviar = getBytes();

                if (requestStop) {
                    return;
                }
            } else if (tipo == ARQUIVO) {
                String boundary = "----------THEANTONIODIEGO";
                String boundaryMessage = getBoundaryMessage(boundary, parametros, campoArquivo, nomeArquivo, tipoArquivo);
                String endBoundary = "\r\n--" + boundary + "--\r\n";

                conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

                if (requestStop) {
                    return;
                }

                //Pega bytes do arquivo
                byte[] arquivo_bytes = new byte[tamanho];
                arquivo.readFully(arquivo_bytes);
                arquivo.close();
                arquivo = null;

                if (requestStop) {
                    return;
                }

                //Constroi mensagem
                ByteArrayOutputStream mensagem = new ByteArrayOutputStream();

                mensagem.write(boundaryMessage.getBytes());
                mensagem.write(arquivo_bytes);
                mensagem.write(endBoundary.getBytes());

                //Reutilizar bytes arquivo
                enviar = mensagem.toByteArray();
            }

            if (requestStop) {
                return;
            }

            conn.setRequestProperty("Content-Length", Integer.toString(enviar.length));

            out = conn.openDataOutputStream();

            if (requestStop) {
                return;
            }

            ByteArrayInputStream byte_buff = new ByteArrayInputStream(enviar);

            byte[] bug = new byte[1024];

            int enviado = 0;

            for (int read = 0; read != -1; read = byte_buff.read(bug)) {
                out.write(bug, 0, read);
                mensagem = "" + (enviado += read) + "/" + enviar.length;
            }

            if (requestStop) {
                return;
            }

            if (flush) {
                out.flush();
            }

            if (requestStop) {
                return;
            }

            //out.close();
        }

        private String getBoundaryMessage(String boundary, Hashtable param, String fileField, String fileName, String fileType) {
            StringBuffer res = new StringBuffer("--").append(boundary).append("\r\n");

            Enumeration keys = param.keys();

            while (keys.hasMoreElements()) {
                String key = (String) keys.nextElement();
                String value = (String) param.get(key);

                res.append("Content-Disposition: form-data; name=\"").append(key).append("\"\r\n").append("\r\n").append(value).append("\r\n").append("--").append(boundary).append("\r\n");
            }
            res.append("Content-Disposition: form-data; name=\"").append(fileField).append("\"; filename=\"").append(fileName).append("\"\r\n").append("Content-Type: ").append(fileType).append("\r\n\r\n");

            return res.toString();
        }

        private void retorna() throws IOException {
            int response = conn.getResponseCode();

            if (response != HttpConnection.HTTP_OK) {
                System.out.println(conn.getResponseMessage());
                listener.falhaRequisiçao("Problema na requisiçao ");
                requestStop = true;
                mytimer.cancel();
            }

            in = conn.openDataInputStream();
        }
    }

    public void setParametros(Hashtable parametros) {
        if (parametros == null) {
            return;
        }
        this.parametros = parametros;
    }

    public void put(String nome, String valor) {
        parametros.put(nome, valor);
    }

    public void doPost(boolean background) {
        this.requestStop = false;
        mytimer = new Timer();

        if (!background) {
            new Thread(this).start();
        }

        mytimer.schedule(new doPoster(), 500);
    }

    public void doCancel() {
        this.requestStop = true;
        mytimer.cancel();
        closeAll();
        listener.requisicaoCancelada();
    }

    public static String readLine(DataInputStream in) {
        ByteArrayOutputStream bytes_linha = new ByteArrayOutputStream();

        while (true) {
            try {
                int c = in.read();

                if (c == -1 || (char) c == '\n') {
                    break;
                }

                if ((char) c != '\r') {
                    bytes_linha.write(c);
                    bytes_linha.flush();
                }
            } catch (IOException ex) {
                return "";
            }
        }

        try {
            return new String(bytes_linha.toByteArray(), "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            return new String(bytes_linha.toByteArray());
        }
    }

    private void closeAll() {
        try {
            if (in != null) {
                in.close();
                in = null;
            }

            if (out != null) {
                out.close();
                out = null;
            }

            if (conn != null) {
                conn.close();
                conn = null;
            }

        } catch (IOException ex) {
            if (Recados.getInstance().config.isErros()) {
                Alert alert = new Alert("Erro", "Problema ao desconectar", null, AlertType.ERROR);
                Recados.getInstance().setCurrent(alert);
            }
        }
    }

    protected void paint(Graphics g) {
        g.setColor(0);
        g.fillRect(0, 0, getWidth(), getHeight());

        g.setColor(0xffffff);

        int msg_width = g.getFont().stringWidth(mensagem);

        int centro_horizontal = (getWidth() - msg_width) / 2;
        int centro_vertical = (getHeight() - g.getFont().getHeight()) / 2;

        g.drawString(mensagem, centro_horizontal, centro_vertical, 0);

        String pontos = null;

        if (dots == 1) {
            pontos = ".";
        } else if (dots == 2) {
            pontos = "..";
        } else if (dots == 3) {
            pontos = "...";
        }

        g.drawString(pontos, centro_horizontal, centro_vertical + g.getFont().getHeight() + 1, 0);

        dots++;

        if (dots > 3) {
            dots = 1;
        }
    }

    public void commandAction(Command c, Displayable d) {
        if (c == cmdCancelar) {
            doCancel();
        }
    }

    public void setListener(HttpListener listener) {
        this.listener = listener;
    }

    public void setArquivo(String fileField, String fileName, String fileType, int tamanho, DataInputStream arquivo) {
        this.campoArquivo = fileField;
        this.nomeArquivo = fileName;
        this.tipoArquivo = fileType;
        this.tamanho = tamanho;
        this.arquivo = arquivo;
        this.tipo = ARQUIVO;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}
